////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2012 Kentaro Sekimoto  All rights reserved.
////////////////////////////////////////////////////////////////////////////

#ifndef FM3_GPIO_H_
#define FM3_GPIO_H_

#include <tinyhal.h>
#include "../FM3.h"

#define FM3_GPIO_INT
#ifdef FM3_GPIO_INT
#define FM3_GPIO_POLLING_INTERVAL    5000    // 5ms
#define MAX_GPIO_INT    20
#endif

#define GPIO_PFR(port)  *((volatile UINT32*)(FM3_GPIO_BASE + 0x000UL + ((port) << 2)))
#define GPIO_PCR(port)  *((volatile UINT32*)(FM3_GPIO_BASE + 0x100UL + ((port) << 2)))
#define GPIO_DDR(port)  *((volatile UINT32*)(FM3_GPIO_BASE + 0x200UL + ((port) << 2)))
#define GPIO_PDIR(port) *((volatile UINT32*)(FM3_GPIO_BASE + 0x300UL + ((port) << 2)))
#define GPIO_PDOR(port) *((volatile UINT32*)(FM3_GPIO_BASE + 0x400UL + ((port) << 2)))
#define GPIO_EPFR(port) *((volatile UINT32*)(FM3_GPIO_BASE + 0x600UL + ((port) << 2)))
#define GPIO_PZR(port)  *((volatile UINT32*)(FM3_GPIO_BASE + 0x700UL + ((port) << 2)))

#define GPIO_PORT(pin)  (pin >> 4)
#define GPIO_MASK(pin)  (1 << (pin & 0xF))

#define DEFAULT_GPIO_ATTRIBUTE  (GPIO_ATTRIBUTE_INPUT | GPIO_ATTRIBUTE_OUTPUT)

#ifdef MB9BF618T
#define FM3_GPIO_MAX_PORTS  16
#define FM3_GPIO_MAX_PINS   (FM3_GPIO_MAX_PORTS * 16)
#define FM3_IRQ_MAX 32
#else
#ifdef MB9BF506N
#define FM3_GPIO_MAX_PORTS  9
#define FM3_GPIO_MAX_PINS   (FM3_GPIO_MAX_PORTS * 16)
#define FM3_IRQ_MAX 8
#else
#define FM3_GPIO_MAX_PORTS  9
#define FM3_GPIO_MAX_PINS   (FM3_GPIO_MAX_PORTS * 16)
#define FM3_IRQ_MAX 8
#endif
#endif

struct FM3_INT_PIN
{
    GPIO_PIN sel0;
    GPIO_PIN sel1;
    GPIO_PIN sel2;
};

struct PIN_ISR_DESCRIPTOR
{
    static const UINT8 c_Flags_Debounce        = 0x01;
    static const UINT8 c_Flags_RequireLowEdge  = 0x02;
    static const UINT8 c_Flags_RequireHighEdge = 0x04;
    static const UINT8 c_Status_AllowLowEdge   = 0x01;
    static const UINT8 c_Status_AllowHighEdge  = 0x02;

    HAL_COMPLETION m_completion;
    GPIO_INTERRUPT_SERVICE_ROUTINE m_isr;
    void *m_param;
    GPIO_PIN m_pin;
    GPIO_INT_EDGE m_intEdge;
    UINT8 m_flags;
    UINT8 m_status;

    static void Fire(void *arg);
};

#define INTNO(no,mode)  ((mode << 5) + no)
#define NOINT   (0xff)

#define PPP 0xff

#define P00 0x00
#define P01 0x01
#define P02 0x02
#define P03 0x03
#define P04 0x04
#define P05 0x05
#define P06 0x06
#define P07 0x07
#define P08 0x08
#define P09 0x09
#define P0A 0x0A
#define P0B 0x0B
#define P0C 0x0C
#define P0D 0x0D
#define P0E 0x0E
#define P0F 0x0F

#define P10 0x10
#define P11 0x11
#define P12 0x12
#define P13 0x13
#define P14 0x14
#define P15 0x15
#define P16 0x16
#define P17 0x17
#define P18 0x18
#define P19 0x19
#define P1A 0x1A
#define P1B 0x1B
#define P1C 0x1C
#define P1D 0x1D
#define P1E 0x1E
#define P1F 0x1F

#define P20 0x20
#define P21 0x21
#define P22 0x22
#define P23 0x23
#define P24 0x24
#define P25 0x25
#define P26 0x26
#define P27 0x27
#define P28 0x28
#define P29 0x29
#define P2A 0x2A
#define P2B 0x2B
#define P2C 0x2C
#define P2D 0x2D
#define P2E 0x2E
#define P2F 0x2F

#define P30 0x30
#define P31 0x31
#define P32 0x32
#define P33 0x33
#define P34 0x34
#define P35 0x35
#define P36 0x36
#define P37 0x37
#define P38 0x38
#define P39 0x39
#define P3A 0x3A
#define P3B 0x3B
#define P3C 0x3C
#define P3D 0x3D
#define P3E 0x3E
#define P3F 0x3F

#define P40 0x40
#define P41 0x41
#define P42 0x42
#define P43 0x43
#define P44 0x44
#define P45 0x45
#define P46 0x46
#define P47 0x47
#define P48 0x48
#define P49 0x49
#define P4A 0x4A
#define P4B 0x4B
#define P4C 0x4C
#define P4D 0x4D
#define P4E 0x4E
#define P4F 0x4F

#define P50 0x50
#define P51 0x51
#define P52 0x52
#define P53 0x53
#define P54 0x54
#define P55 0x55
#define P56 0x56
#define P57 0x57
#define P58 0x58
#define P59 0x59
#define P5A 0x5A
#define P5B 0x5B
#define P5C 0x5C
#define P5D 0x5D
#define P5E 0x5E
#define P5F 0x5F

#define P60 0x60
#define P61 0x61
#define P62 0x62
#define P63 0x63
#define P64 0x64
#define P65 0x65
#define P66 0x66
#define P67 0x67
#define P68 0x68
#define P69 0x69
#define P6A 0x6A
#define P6B 0x6B
#define P6C 0x6C
#define P6D 0x6D
#define P6E 0x6E
#define P6F 0x6F

#define P70 0x70
#define P71 0x71
#define P72 0x72
#define P73 0x73
#define P74 0x74
#define P75 0x75
#define P76 0x76
#define P77 0x77
#define P78 0x78
#define P79 0x79
#define P7A 0x7A
#define P7B 0x7B
#define P7C 0x7C
#define P7D 0x7D
#define P7E 0x7E
#define P7F 0x7F

#define P80 0x80
#define P81 0x81
#define P82 0x82
#define P83 0x83
#define P84 0x84
#define P85 0x85
#define P86 0x86
#define P87 0x87
#define P88 0x88
#define P89 0x89
#define P8A 0x8A
#define P8B 0x8B
#define P8C 0x8C
#define P8D 0x8D
#define P8E 0x8E
#define P8F 0x8F

#define P90 0x90
#define P91 0x91
#define P92 0x92
#define P93 0x93
#define P94 0x94
#define P95 0x95
#define P96 0x96
#define P97 0x97
#define P98 0x98
#define P99 0x99
#define P9A 0x9A
#define P9B 0x9B
#define P9C 0x9C
#define P9D 0x9D
#define P9E 0x9E
#define P9F 0x9F

#define PA0 0xA0
#define PA1 0xA1
#define PA2 0xA2
#define PA3 0xA3
#define PA4 0xA4
#define PA5 0xA5
#define PA6 0xA6
#define PA7 0xA7
#define PA8 0xA8
#define PA9 0xA9
#define PAA 0xAA
#define PAB 0xAB
#define PAC 0xAC
#define PAD 0xAD
#define PAE 0xAE
#define PAF 0xAF

#define PB0 0xB0
#define PB1 0xB1
#define PB2 0xB2
#define PB3 0xB3
#define PB4 0xB4
#define PB5 0xB5
#define PB6 0xB6
#define PB7 0xB7
#define PB8 0xB8
#define PB9 0xB9
#define PBA 0xBA
#define PBB 0xBB
#define PBC 0xBC
#define PBD 0xBD
#define PBE 0xBE
#define PBF 0xBF

#define PC0 0xC0
#define PC1 0xC1
#define PC2 0xC2
#define PC3 0xC3
#define PC4 0xC4
#define PC5 0xC5
#define PC6 0xC6
#define PC7 0xC7
#define PC8 0xC8
#define PC9 0xC9
#define PCA 0xCA
#define PCB 0xCB
#define PCC 0xCC
#define PCD 0xCD
#define PCE 0xCE
#define PCF 0xCF

#define PD0 0xD0
#define PD1 0xD1
#define PD2 0xD2
#define PD3 0xD3
#define PD4 0xD4
#define PD5 0xD5
#define PD6 0xD6
#define PD7 0xD7
#define PD8 0xD8
#define PD9 0xD9
#define PDA 0xDA
#define PDB 0xDB
#define PDC 0xDC
#define PDD 0xDD
#define PDE 0xDE
#define PDF 0xDF

#define PE0 0xE0
#define PE1 0xE1
#define PE2 0xE2
#define PE3 0xE3
#define PE4 0xE4
#define PE5 0xE5
#define PE6 0xE6
#define PE7 0xE7
#define PE8 0xE8
#define PE9 0xE9
#define PEA 0xEA
#define PEB 0xEB
#define PEC 0xEC
#define PED 0xED
#define PEE 0xEE
#define PEF 0xEF

#define PF0 0xF0
#define PF1 0xF1
#define PF2 0xF2
#define PF3 0xF3
#define PF4 0xF4
#define PF5 0xF5
#define PF6 0xF6
#define PF7 0xF7
#define PF8 0xF8
#define PF9 0xF9
#define PFA 0xFA
#define PFB 0xFB
#define PFC 0xFC
#define PFD 0xFD
#define PFE 0xFE
#define PFF 0xFF

#define FM3_INT_LEVEL_LOW   0
#define FM3_INT_LEVEL_HIGH  1
#define FM3_INT_EDGE_HIGH   2
#define FM3_INT_EDGE_LOW    3

#ifdef FM3_GPIO_EXT_INT
void __attribute__((interrupt)) ExInt0_7(void);
void __attribute__((interrupt)) ExInt8_31(void);
#endif

#endif /* FM3_GPIO_H_ */
